
include('sh_mover_gun_actorproperties.lua')
include('sh_mover_gun_cameraproperties.lua')

local STool = {}
CatmullRomCams.SToolMethods.ActorMover  = STool

local mouseOverHighlightEntity = nil
local selectedNPC = nil
local selectedNPCPathNode = nil
local selectedCameraPathNode = nil

local toolState = -1

local function npc_doNotify( message, symbol, user )
  if SERVER then
    user:SendLua("GAMEMODE:AddNotify(\"" .. message .. "\", " .. symbol .. ", \"5\"); surface.PlaySound( \"ambient/water/drip" .. math.random(1, 4) .. ".wav\" )")
  end
end

function STool.IsValid(ent)
	if(ent && ent:IsValid()) then
		return true
	else
		return false
	end
end

function STool.IsPathNode(ent)

	if not STool.IsValid(ent) then
		return false
	end

	return ent:GetClass() == "sent_pathnode"
end

function STool.IsActor(ent)
	return (STool.IsValid(ent) and ent:IsNPC())
end

function STool.IsCameraNode(ent)

	if not STool.IsValid(ent) then
		return false
	end

	return ent:GetClass() == "sent_camera"
end

function STool.IsParticleSystem(ent)

	if not STool.IsValid(ent) then
		return false
	end

	return ent:GetClass() == "sent_particlesystem"
end

if CLIENT then
	language.Add( "Tool_npc_mover_gun_name", "Actor Animation" )
	language.Add( "Tool_npc_mover_gun_desc", "Allows you to specify and control the animation of actors" )
	language.Add( "Tool_npc_mover_gun_0", "TODO" )
end

STool.LEFT_CLICK = 1
STool.RIGHT_CLICK = 2

STool.HIT_UNKNOWN = -1
STool.HIT_WORLD = 1
STool.HIT_ACTOR = 2
STool.HIT_PATHNODE = 3
STool.HIT_CAMERANODE = 4

STool.FUNCTION_ID_PLAY = 0
STool.FUNCTION_ID_UPDATE_CAMERANODE = 1
STool.FUNCTION_ID_UPDATE_PARTICLESYSTEM = 4
STool.FUNCTION_ID_TOGGLE_VIEW_LINKACHORS = 5
STool.FUNCTION_ID_TOGGLE_VIEW_GUN = 6
STool.FUNCTION_ID_STRIP_WEAPONS = 2
STool.FUNCTION_ID_TOGGLE_VIEW_PERSP = 3

STool.TOOLSTATE_IDLE = 0
STool.TOOLSTATE_PLOTACTORPATHWAY = 1
STool.TOOLSTATE_LINKACTORCAMERAPATH = 2
STool.TOOLSTATE_PLOTCAMERATRACK = 3
STool.TOOLSTATE_LINKACTORTOPATH = 4
STool.TOOLSTATE_PLAYACTORS = 5
STool.TOOLSTATE_CREATEACTOR = 6
STool.TOOLSTATE_PLOTPARTICLESYSTEM = 7

local MARKER_RADIUS = 4

local function IsValid(entity)
	return entity and entity:IsValid()
end

local function PrintError(code)
	print("********************")
	print("* ERROR")
	print("* Code: " .. code)
	print("* Please tell Gareth")
	return false
end

function ProcessTrace()

	//TODO: could be problematic for MP
	local localPlayer = player.GetByID(1)

	tracePlayer = {}
	tracePlayer.start  = localPlayer:GetShootPos()
	tracePlayer.endpos = tracePlayer.start + (localPlayer:GetAimVector() * 99999999)
	tracePlayer.filter = localPlayer
	tracePlayer = util.TraceLine(tracePlayer)
	
	local hitType = STool.HIT_UNKNOWN

	//Provide visual feedback
	if(mouseOverHighlightEntity) then

		if mouseOverHighlightEntity:IsValid() == false then
			mouseOverHighlightEntity = nil
		elseif(mouseOverHighlightEntity != tracePlayer.Entity) then
		
			if(mouseOverHighlightEntity:GetClass() == "node_actorpath") then	
				mouseOverHighlightEntity.BaseClass.SetHighlighting(mouseOverHighlightEntity, 0)
			end

			if(mouseOverHighlightEntity:GetClass() == "sent_catmullrom_camera") then
				mouseOverHighlightEntity:SetNWEntity("PreviewLink", nil)
			end
		end
	end
	mouseOverHighlightEntity = tracePlayer.Entity

	if (tracePlayer.HitWorld) then		
		hitType = STool.HIT_WORLD

	elseif (tracePlayer.Entity) then
		
		local entityClassname = tracePlayer.Entity:GetClass()
		
		if(string.find(entityClassname, "node_actorpath", 1) == 1) then
			hitType = STool.HIT_PATHNODE
		elseif(string.find(entityClassname, "npc_", 1) == 1) then
			hitType = STool.HIT_ACTOR
		elseif(string.find(entityClassname, "sent_catmullrom_camera", 1) == 1) then
			hitType = STool.HIT_CAMERANODE
		end
	end

	return tracePlayer, hitType
end


function STool.PlotPathway( thisPlayer, self, trace)

	if CLIENT then
		return
	end

	selectedNPC = nil
	selectedNPCPathNode = nil
	selectedCameraPathNode = nil

	local playerIndex = thisPlayer:UniqueID()
	local pathwayIndex = self:GetClientInfo( "actor_pathway_name" )
	
	if pathwayIndex == nil or pathwayIndex == "" then
		pathwayIndex = string.format("MyPathway%u",self:GetClientNumber( "default_actor_pathway_num"))
		thisPlayer:ConCommand(string.format("npc_mover_gun_camera_track_name %u",(self:GetClientNumber( "default_actor_pathway_num" ) + 1)))
	end

	CatmullRomCams.Tracks[playerIndex] = CatmullRomCams.Tracks[playerIndex] or {}
	CatmullRomCams.Tracks[playerIndex][pathwayIndex] = CatmullRomCams.Tracks[playerIndex][pathwayIndex] or {}

	local nodeIndex = #CatmullRomCams.Tracks[playerIndex][pathwayIndex] + 1
	local pathNodeEnt = ents.Create("sent_pathnode")
	if not IsValid(pathNodeEnt) then 
		return PrintError("000003")
	end		

	pathNodeEnt.BaseClass.SetIndexData(pathNodeEnt, {playerIdx = playerIndex,trackIdx = pathwayIndex,nodeIdx = nodeIndex})
	pathNodeEnt:Spawn()

	local nodePosition = trace.HitPos + (trace.HitNormal * 10)
	pathNodeEnt:SetPos(nodePosition)

	CatmullRomCams.Tracks[playerIndex] = CatmullRomCams.Tracks[playerIndex] or {}
	CatmullRomCams.Tracks[playerIndex][pathwayIndex] = CatmullRomCams.Tracks[playerIndex][pathwayIndex] or {}

	CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex] = pathNodeEnt

	if CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex - 1] and CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex - 1]:IsValid() then
		CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex - 1]:DeleteOnRemove(pathNodeEnt)
		CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex - 1]:SetNWEntity("ChildCamera", pathNodeEnt)

		CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex - 1].NextNode = CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex]
		CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex].PrevNode = CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex - 1]
	else
		pathNodeEnt:SetNWBool("IsMasterController", true)
		pathNodeEnt:SetNWEntity("ControllingPlayer", thisPlayer)
	end
	
	pathNodeEnt:SetNWEntity("MasterController", CatmullRomCams.Tracks[playerIndex][pathwayIndex][1])

	undo.Create("PathNode")
	undo.AddEntity(pathNodeEnt)
	
	if nodeIndex ~= 1 then
		undo.AddEntity(constraint.NoCollide(pathNodeEnt, CatmullRomCams.Tracks[playerIndex][pathwayIndex][1], 0, 0))
	end
	
	undo.SetPlayer(thisPlayer)
	undo.Finish()	
	
	thisPlayer:AddCleanup("catmullrom_cameras", pathNodeEnt)
end

function STool.PlotParticleSystem( thisPlayer, self, trace)

	if CLIENT then
		return
	end

	selectedNPC = nil
	selectedNPCPathNode = nil
	selectedCameraPathNode = nil

	local particleSystem = ents.Create("sent_particlesystem")
	if not IsValid(particleSystem) then 
		return PrintError("Failed to create particle system")
	end		

	particleSystem:Spawn()

	particleSystem:SetAngles(Angle(0,0,0))
	particleSystem:SetPos(trace.HitPos + (trace.HitNormal * 10))
	
	undo.Create("CatmullRomCamera")
	undo.AddEntity(particleSystem)
	
	undo.SetPlayer(thisPlayer)
	undo.Finish()	
	
	thisPlayer:AddCleanup("catmullrom_cameras", particleSystem)
end

function STool.PlotTrack( thisPlayer, self, trace)

	local playerIndex = thisPlayer:UniqueID()
	local pathwayIndex = self:GetClientInfo( "camera_track_name" )

	if pathwayIndex == nil or pathwayIndex == "" then

		pathwayIndex = string.format("MyTrack%u",self:GetClientNumber( "default_camera_track_num"))
		thisPlayer:ConCommand(string.format("npc_mover_gun_camera_track_name %u",(self:GetClientNumber( "default_camera_track_num" ) + 1)))
	end

	CatmullRomCams.Tracks[playerIndex]      = CatmullRomCams.Tracks[playerIndex]      or {}
	CatmullRomCams.Tracks[playerIndex][pathwayIndex] = CatmullRomCams.Tracks[playerIndex][pathwayIndex] or {}
	
	local nodeIndex = #CatmullRomCams.Tracks[playerIndex][pathwayIndex] + 1	
	
	
	local camera = ents.Create("sent_camera")
	
	if not (camera and camera.IsValid and camera:IsValid()) then 
		npc_doNotify("ERROR CODE: 0002, please tell the developer", "NOTIFY_ERROR", self:GetOwner())	
		return 
	end
	
	local ang = thisPlayer:EyeAngles()
	

	camera.BaseClass.SetIndexData(camera, {playerIdx = playerIndex,trackIdx = pathwayIndex,nodeIdx = nodeIndex})
	camera:Spawn()	

	camera:SetAngles(ang)
	camera:SetPos(trace.StartPos)
	
	camera:SetPlayer(thisPlayer)


	if CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex - 1] and CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex - 1]:IsValid() then
		CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex - 1]:DeleteOnRemove(camera)
		CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex - 1]:SetNWEntity("ChildCamera", camera)
		
	else
		camera:SetNWBool("IsMasterController", true)
		camera:SetNWEntity("ControllingPlayer", thisPlayer)
	
		camera:SetKey(pathwayIndex)
	end
	
	CatmullRomCams.Tracks[playerIndex][pathwayIndex][nodeIndex] = camera
	
	camera:SetNWEntity("MasterController", CatmullRomCams.Tracks[playerIndex][pathwayIndex][1])
	
	undo.Create("CatmullRomCamera")
	undo.AddEntity(camera)
	
	if nodeIndex ~= 1 then
		undo.AddEntity(constraint.NoCollide(camera, CatmullRomCams.Tracks[playerIndex][pathwayIndex][1], 0, 0))
	end
	
	undo.SetPlayer(thisPlayer)
	undo.Finish()
	
	thisPlayer:AddCleanup("catmullrom_cameras", camera)

end


function STool.LinkCameraActorPathway( thisPlayer, self, trace)

	if(not (selectedCameraPathNode && selectedCameraPathNode:IsValid() 
		&& selectedNPCPathNode && selectedNPCPathNode:IsValid())) then
		return
	end

	local playerIndex = thisPlayer:UniqueID()

		for k, v in pairs(CatmullRomCams.Tracks[playerIndex]) do
			for l, w in pairs(CatmullRomCams.Tracks[playerIndex][k]) do

				local camera = CatmullRomCams.Tracks[playerIndex][k][l]
				if tracePlayer.Entity == camera then
					
					CatmullRomCams.Tracks[playerIndex][k][l]:AssignPathNode(selectedNPCPathNode)
	
					selectedNPCPathNode = nil
					selectedCameraPathNode:SetNWEntity("PreviewLink", nil)
					selectedCameraPathNode = nil
					break
				end

				if selectedNPCPathNode == nil && selectedCameraPathNode == nill then
					break
				end

			end
		end


	trace.Entity:SetMaterial("models/shiny")

end

function STool.LeftClick( self, trace )
		
	if CLIENT then
	return
	end

	local ply   = self:GetOwner()
	local pathwayIndex = self:GetClientInfo( "actor_pathway_name" );

	tracePlayer, hitType = ProcessTrace()

	local toolState = self:GetClientNumber("toolstate")

	if(toolState == STool.TOOLSTATE_IDLE) then

	elseif(toolState == STool.TOOLSTATE_PLOTPARTICLESYSTEM) then

		if(hitType == STool.HIT_WORLD) then
			
			STool.PlotParticleSystem( ply, self, trace)

		else
			PrintError("Opps, make sure you click an empty space during particle system mode")
		end
		
	//We are in 'attach actor to the path node' mode
	elseif(toolState == STool.TOOLSTATE_LINKACTORTOPATH) then

		STool.SetState(self, STool.TOOLSTATE_IDLE)

		if(hitType == STool.HIT_ACTOR) then
	
			if STool.IsPathNode(selectedNPCPathNode) and STool.IsActor(trace.Entity) then
				

				if selectedNPCPathNode:AssignActorToTrack(trace.Entity) == false then
					PrintError("Failed to assign actor to track")
				end

				//Very important that this is set to nil as it prevents
				//'LeftClick' functions cycles from initalizing a draw line
				//from this node (because the tool state dosn't get set immediatly)
				selectedNPCPathNode.BaseClass.SetConstructPoint(selectedNPCPathNode, false, nil) 
				selectedNPCPathNode = nil

			else
				PrintError("Select node not path or clicked object not actor")
			end

		else
			npc_doNotify("Opps, make sure you click on an actor. You can right click to cancel attaching", "NOTIFY_ERROR", self:GetOwner())
		end

	//We are in the 'plot actor pathway' mode
	elseif(toolState == STool.TOOLSTATE_PLOTACTORPATHWAY) then

		if hitType == STool.HIT_WORLD then
	
			STool.PlotPathway( ply, self, trace)

		else
			npc_doNotify("Whoops, make sure you don't click on other object types", "NOTIFY_ERROR", self:GetOwner())
		end

	//We are in the 'plot camera track' mode
	elseif(toolState == STool.TOOLSTATE_PLOTCAMERATRACK) then
	
		if(hitType == STool.HIT_WORLD) then
	
			STool.PlotTrack( ply, self, trace)

		else
			npc_doNotify("Whoops, make sure you don't click on other object types", "NOTIFY_ERROR", self:GetOwner())
		end
	
	//We are trying to link a camera pathway to an actor pathway
	elseif(toolState == STool.TOOLSTATE_LINKACTORCAMERAPATH) then

		STool.SetState(self, STool.TOOLSTATE_IDLE)

		if(hitType == STool.HIT_PATHNODE) then
			
			if STool.IsCameraNode(selectedCameraPathNode) and STool.IsPathNode(trace.Entity) then
			
				local actorPathRootNode = trace.Entity.BaseClass.GetRootNode(trace.Entity)
				if selectedCameraPathNode:AssignActorPathwayToTrack(actorPathRootNode) == false then
					PrintError("Failed to assign actor pathway to camera track")
				end
			else
				PrintError("Selected node invalid or not correct type")
			end

			//Very important that this is done
			selectedCameraPathNode.BaseClass.SetConstructPoint(selectedCameraPathNode, false, nil) 
			selectedCameraPathNode = nil
		else
		
			selectedCameraPathNode.BaseClass.SetConstructPoint(selectedCameraPathNode, false, nil) 
			selectedCameraPathNode = nil
			//npc_doNotify("Opps, make sure you click on a pathnode. You can right click to cancel attaching", "NOTIFY_ERROR", self:GetOwner())
		end
			
	end
end

function STool.SetState(toolSelf, stateValue)
	if toolSelf == nil then
		PrintError("stools_toolSelf == nil")
		return
	end

	local ownerEnt = toolSelf:GetOwner()
	if STool.IsValid( ownerEnt ) and ownerEnt:IsPlayer() then
		ownerEnt:ConCommand( "npc_mover_gun_toolstate " .. stateValue)
	else
		PrintError("stools_7")
	end
end

local lastClientEntityID = -1
function STool.HandleClientFunction(self)

	local clientEntityID = self:GetClientNumber("entitIDfromclient")
	self:GetOwner():ConCommand( "npc_mover_gun_entitIDfromclient -1")
	
	 if clientEntityID != -1 && lastClientEntityID != clientEntityID then

		local entity = ents.GetByIndex(clientEntityID)
		if !STool.IsValid(entity) then
			return
		end

		lastClientEntityID = clientEntityID

		local clientFunctionID = self:GetClientNumber("functIDfromclient")
		self:GetOwner():ConCommand( "npc_mover_gun_functIDfromclient -1")

		 if clientFunctionID == STool.FUNCTION_ID_PLAY then
			if STool.IsCameraNode(entity) then
				entity:PlayCameraTrack(self:GetOwner())
			end

		 elseif clientFunctionID == STool.FUNCTION_ID_STRIP_WEAPONS then
			if entity:IsPlayer() then
				entity:StripWeapons()
			end

		 elseif clientFunctionID == STool.FUNCTION_ID_TOGGLE_VIEW_PERSP then
			if entity:IsPlayer() then

				local toggleViewPersp = 1
				if self:GetClientNumber("third_person") == 1 then
					toggleViewPersp = 0
				end
				
				self:GetOwner():ConCommand( "npc_mover_gun_third_person " .. toggleViewPersp)
				if self:GetClientNumber("third_person") == 0 then
					self:GetOwner():ConCommand( "firstperson")
				else
					self:GetOwner():ConCommand( "thirdperson")
				end
			end

		elseif clientFunctionID == STool.FUNCTION_ID_TOGGLE_VIEW_GUN then

			if entity:IsPlayer() then

				local toggleViewWeapon = 1
				if self:GetClientNumber("show_weapon") == 1 then
					toggleViewWeapon = 0
				end

				self:GetOwner():ConCommand( "npc_mover_gun_show_weapon " .. toggleViewWeapon)
				//self:GetOwner():ConCommand( "sv_cheats 1")
				self:GetOwner():DrawViewModel(self:GetClientNumber("show_weapon") == 0)
			end

		elseif clientFunctionID == STool.FUNCTION_ID_TOGGLE_VIEW_LINKACHORS then

			local toggleViewObject = 1
			if self:GetClientNumber("show_objects") == 1 then
				toggleViewObject = 0
			end
			self:GetOwner():ConCommand( "npc_mover_gun_show_objects " .. toggleViewObject)
			//The show objects over ride is stored in the player because its local
			//and accessible to all that it effects
			if entity:IsPlayer() then
				self:GetOwner():SetNWInt( "show_objects", toggleViewObject)
			end

		 elseif clientFunctionID == STool.FUNCTION_ID_UPDATE_PARTICLESYSTEM then
			if STool.IsParticleSystem(entity) then

				entity:SetNWInt("system_population", self:GetClientNumber("system_population"))
				entity:SetNWInt("system_state", self:GetClientNumber("system_state"))
				entity:SetNWInt("system_show_origin", self:GetClientNumber("system_show_origin"))
				entity:SetNWFloat("generation_dirx", self:GetClientNumber("generation_dirx"))
				entity:SetNWFloat("generation_diry", self:GetClientNumber("generation_diry"))
				entity:SetNWFloat("generation_dirz", self:GetClientNumber("generation_dirz"))
				entity:SetNWFloat("generation_dirvar", self:GetClientNumber("generation_dirvar"))
				entity:SetNWFloat("generation_disx", self:GetClientNumber("generation_disx"))
				entity:SetNWFloat("generation_disy", self:GetClientNumber("generation_disy"))
				entity:SetNWFloat("generation_disz", self:GetClientNumber("generation_disz"))
				entity:SetNWFloat("generation_acex", self:GetClientNumber("generation_acex"))
				entity:SetNWFloat("generation_acey", self:GetClientNumber("generation_acey"))
				entity:SetNWFloat("generation_acez", self:GetClientNumber("generation_acez"))
				entity:SetNWInt("generation_acevar", self:GetClientNumber("generation_acevar"))
				entity:SetNWFloat("param_rad", self:GetClientNumber("param_rad"))
				entity:SetNWInt("param_radvar", self:GetClientNumber("param_radvar"))
				entity:SetNWFloat("param_life", self:GetClientNumber("param_life"))
				entity:SetNWInt("param_lifevar", self:GetClientNumber("param_lifevar"))
				entity:SetNWFloat("param_rotate", self:GetClientNumber("param_rotate"))
				entity:SetNWInt("param_rotatevar", self:GetClientNumber("param_rotatevar"))
				entity:SetNWString("param_billboard", self:GetClientInfo("param_billboard"))

			end
		 elseif clientFunctionID == STool.FUNCTION_ID_UPDATE_CAMERANODE then
			if STool.IsCameraNode(entity) then

				entity:SetNWInt("camera_zoom", self:GetClientNumber("camera_zoom"))
				entity:SetNWInt("show_prop_links", self:GetClientNumber("show_prop_links"))

				if self:GetClientNumber("show_view_finder") == 1 then
					entity:ShowViewFinder(self:GetClientNumber("show_view_finder") == 1)
					self:GetOwner():ConCommand( "npc_mover_gun_show_view_finder 0")
				end

				entity:SetNWInt("show_pathway_triggers", self:GetClientNumber("show_pathway_triggers"))
				entity:SetNWInt("playback_selected", self:GetClientNumber("playback_selected"))
				entity:SetNWInt("duration_transition", self:GetClientNumber("duration_transition"))
				entity:SetNWInt("duration_wait", self:GetClientNumber("duration_wait"))
				entity:SetNWInt("shake_agression", self:GetClientNumber("shake_agression"))
				entity:SetNWInt("shake_frequency", self:GetClientNumber("shake_frequency"))
				entity:SetNWInt("shake_type", self:GetClientNumber("shake_type"))
				entity:SetNWInt("shake_center", self:GetClientNumber("shake_center"))
			   
				entity.BaseClass.GetRootNode(entity):SetNWString("framing_type", self:GetClientInfo("framing_type"))
				
			end
		 end

	else
		if clientEntityID == -1 then
			lastClientEntityID = -1
		end
	 end

end

function STool.Think(self)

	if CLIENT then
		return
	end
	

	tracePlayer, hitType = ProcessTrace()
	traceEntity = tracePlayer.Entity
	toolState = self:GetClientNumber("toolstate")

	STool.HandleClientFunction(self)

	if(toolState == STool.TOOLSTATE_IDLE) then

		if traceEntity then
			if not traceEntity:IsPlayer() then 
				if STool.IsPathNode(traceEntity) or STool.IsCameraNode(traceEntity) then
					traceEntity.BaseClass.SetHighlighting(traceEntity, 1)
				end
			end
		end
			
	//This block controls the update behaviour during plotting of the camera track
	elseif(toolState == STool.TOOLSTATE_PLOTCAMERATRACK) then


	//Client asked us to create an actor
	elseif(toolState == STool.TOOLSTATE_CREATEACTOR) then
	
		STool.SetState(self, STool.TOOLSTATE_IDLE)

		local actorPosition = tracePlayer.HitPos + (tracePlayer.HitNormal * 15)
		//ents.Create(



	//This code tells the track to begin 'playing back' any assigned actors with
	//respective animations. It enables the user to invoke this playback from any
	//node on the track, ie it automatically indexes to the root node
	elseif(toolState == STool.TOOLSTATE_PLAYACTORS) then

		STool.SetState(self, STool.TOOLSTATE_IDLE)

		local invokedEntityIdx = self:GetClientNumber("entitIDfromclient")
		self:GetOwner():ConCommand( "npc_mover_gun_entitIDfromclient -1")

		local pathNodePlayInvoke = nil
		if invokedEntityIdx >= 0 then 
			pathNodePlayInvoke = ents.GetByIndex(invokedEntityIdx)
			if not STool.IsValid(pathNodePlayInvoke) then
				PrintError("stools_STool.IsValid(pathNodePlayInvoke)")
				return
			end
		else
			PrintError("stools_invokedEntityIdx >= 0")
			return
		end
		if not STool.IsPathNode( pathNodePlayInvoke ) then
			PrintError("not STool.IsPathNode( pathNodePlayInvoke )")
			return
		end
			
		pathNodePlayInvoke:PlayActors(0)

	elseif(toolState == STool.TOOLSTATE_PLOTACTORPATHWAY) then

	//This code takes care of rendering the 'preview link' line from the
	//path node to prospective actors. Its purpose is to provide visual feedback
	//during the construction process
	elseif(toolState == STool.TOOLSTATE_LINKACTORTOPATH) then
	
		if not STool.IsValid( selectedNPCPathNode ) then

			//This is messy but the only way I could figure out how to
			//get an entity sent from the client/context meun to the 
			//server/tool. Its basically telling us the path node that 
			//we want to draw a link from
			local invokedEntityIdx = self:GetClientNumber("entitIDfromclient")

			//We have to reset this to allow for subsequent links to be drawn
			//correctly
			self:GetOwner():ConCommand( "npc_mover_gun_entitIDfromclient -1")
			if invokedEntityIdx >= 0 then
				local invokedEntity = ents.GetByIndex(invokedEntityIdx)
				if STool.IsValid(invokedEntity) then
					selectedNPCPathNode = invokedEntity
				else
					PrintError("stools_STool.IsValid(invokedEntity)")
					STool.SetState(self, STool.TOOLSTATE_IDLE)
					return
				end
			else
				//PrintError("stools_invokedEntityIdx >= 0")
				STool.SetState(self, STool.TOOLSTATE_IDLE)
				return
			end
		end

		if not STool.IsPathNode( selectedNPCPathNode ) then
			PrintError("stools_6")
			STool.SetState(self, STool.TOOLSTATE_IDLE)
			return
		end

		local endpointVector = nil
		if tracePlayer.HitNonWorld then
			endpointVector = tracePlayer.Entity:GetPos()
		else
			endpointVector = tracePlayer.HitPos
		end

		selectedNPCPathNode.BaseClass.SetConstructPoint(selectedNPCPathNode, true, endpointVector) 

	elseif(toolState == STool.TOOLSTATE_LINKACTORCAMERAPATH) then
	
		if not STool.IsValid( selectedCameraPathNode ) then

			//This is messy but the only way I could figure out how to
			//get an entity sent from the client/context meun to the 
			//server/tool. Its basically telling us the path node that 
			//we want to draw a link from
			local invokedEntityIdx = self:GetClientNumber("entitIDfromclient")

			//We have to reset this to allow for subsequent links to be drawn
			//correctly
			self:GetOwner():ConCommand( "npc_mover_gun_entitIDfromclient -1")
			if invokedEntityIdx >= 0 then
				local invokedEntity = ents.GetByIndex(invokedEntityIdx)
				if STool.IsValid(invokedEntity) then
					selectedCameraPathNode = invokedEntity
				else
					PrintError("stools_STool.IsValid(invokedEntity)")
					STool.SetState(self, STool.TOOLSTATE_IDLE)
					return
				end
			else
				//PrintError("stools_invokedEntityIdx >= 0")
				STool.SetState(self, STool.TOOLSTATE_IDLE)
				return
			end
		end

		if not STool.IsCameraNode( selectedCameraPathNode ) then
			PrintError("stools_6")
			STool.SetState(self, STool.TOOLSTATE_IDLE)
			return
		end

		local endpointVector = nil
		if tracePlayer.HitNonWorld then
			endpointVector = tracePlayer.Entity:GetPos()
		else
			endpointVector = tracePlayer.HitPos
		end

		selectedCameraPathNode.BaseClass.SetConstructPoint(selectedCameraPathNode, true, endpointVector) 

	end

end

function STool.InvokeProperties(player, tracePlayer)

	if STool.IsValid(player) && player:IsPlayer() then
		local recipientFilter = RecipientFilter()
		recipientFilter:AddPlayer(player)

		local propertiesIdent = "ShowProperties"

		if STool.IsPathNode(tracePlayer.Entity) or STool.IsCameraNode(tracePlayer.Entity) or STool.IsParticleSystem(tracePlayer.Entity) then
			propertiesIdent = propertiesIdent .. tracePlayer.Entity:GetClass()
		elseif STool.IsActor(tracePlayer.Entity) then
			propertiesIdent = propertiesIdent .. "actor"
		elseif STool.IsValid(tracePlayer.Entity) then
			return
		end

		umsg.Start(propertiesIdent, recipientFilter)

		if not STool.IsValid(tracePlayer.Entity) then	//we are right clicking nothing
			umsg.Vector(tracePlayer.HitPos)
		else
			umsg.Entity(tracePlayer.Entity)	//we are right clicking an entity
		end

		umsg.End()	
	end
end

//usermessage.Hook( "req_ShowToolProp", STool.ShowProperties ) 

function STool.RightClick( self,trace )

	if CLIENT then
		return
	end

	tracePlayer, hitType = ProcessTrace()
	local traceEntity = trace.Entity
	local thisPlayer = self:GetOwner()

	STool.InvokeProperties(thisPlayer, tracePlayer)	

	return false
end

function STool.Reload(self, trace )

	STool.SetState(self, STool.TOOLSTATE_PLOTCAMERATRACK) //:Not production code: STool.TOOLSTATE_IDLE)
	selectedNPC = nil
	selectedNPCPathNode = nil
	selectedCameraPathNode = nil

	npc_doNotify("Tool reset", "NOTIFY_ERROR", self:GetOwner())
end

function STool.BuildCPanel(panel)

	panel:AddControl("Header", { Text = "Actor Director", Description = "Used to control actors" })

	panel:AddControl("Label", { Text = "\nSetup:\n", Description = " "})
		panel:AddControl("TextBox", 
	  { Label = "Pathway Name", Description = "A unique indentification for this pathway", 
	  MaxLength = 50, Text = "Pathway1", Command = "npc_mover_gun_actor_pathway_name", 
	  WaitForEnter = false})

  panel:AddControl("Label", { Text = "\nCreate:\n", Description = " "})

	  panel:AddControl("Button", 
	  { Label = "Reset", 
	  Description = " ", Command = "npc_mover_gun_toolstate 0"}) 

	  panel:AddControl("Button", 
	  { Label = "Plot actor pathway", 
	  Description = " ", Command = "npc_mover_gun_toolstate 1"}) 

	  panel:AddControl("Button", 
	  { Label = "Plot camera track", 
	  Description = " ", Command = "npc_mover_gun_toolstate 3"}) 

	  panel:AddControl("Button", 
	  { Label = "Link camera to actor pathway", 
	  Description = " ", Command = "npc_mover_gun_toolstate 2"}) 

	panel:AddControl("Label", { Text = "\nDisplay:\n", Description = " "})
		panel:AddControl("CheckBox", 
	  { Label = "Actor/Pathway relationships", 
	  Description = " ", Command = "npc_mover_gun_showrelation"}) 

		
	panel:AddControl("Label", { Text = "Parameters:", Description = ""})
	panel:AddControl("ListBox", 
	{ Label = "Actor animation", 
	Description = "Choose the animation at a point in the pathway", 
	MenuButton = true,
	Height = 20,
	Command = "npc_mover_gun_showrelationpathway_choose_anim" })
end
